package com.heima.article.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.heima.article.entity.ApArticle;
import com.heima.article.entity.ApHotArticles;
import com.heima.article.mapper.ApHotArticlesMapper;
import com.heima.article.service.IApArticleService;
import com.heima.article.service.IApHotArticlesService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.heima.common.constants.article.ArticleConstans;
import com.heima.common.util.BeanHelper;
import com.heima.common.util.JsonUtils;
import com.heima.model.article.dtos.ArticleDto;
import com.heima.model.article.msg.ArticleBehaviorStreamMsg;
import com.heima.model.article.vo.HotArticleVo;
import org.joda.time.DateTime;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;

import static com.heima.common.constants.article.ArticleConstans.HOT_ARTICLE_LIKE_WEIGHT;

/**
 * <p>
 * 热文章表 服务实现类
 * </p>
 *
 * @author heima
 * @since 2021-03-29
 */
@Service
public class ApHotArticlesServiceImpl extends ServiceImpl<ApHotArticlesMapper, ApHotArticles> implements IApHotArticlesService {

    @Autowired
    private IApArticleService apArticleService;

    @Override
    public void findHotArticle() {
        //获取5天前日期
        String date = DateTime.now().minusDays(5).toString("yyyy-MM-dd 00:00:00");
        //查询数据库中文章列表数据
        QueryWrapper<ApArticle> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(ApArticle::getIsDown,false).
                eq(ApArticle::getIsDelete,false).
                gt(ApArticle::getPublishTime,date);
        List<ApArticle> articleList = apArticleService.list(queryWrapper);
        if(CollectionUtils.isEmpty(articleList)){
            return;
        }
        //计算文章分值
        List<HotArticleVo> hotArticleVoList = getHotApArticle(articleList);
        //缓存热点文章到redis     使用zset存储文章分值   使用hash数据类型存储文章内容
        cacheHotArticleToRedisByChannel(hotArticleVoList);
    }

    @Override
    public void updateHotArticle(ArticleBehaviorStreamMsg streamMsg) {
        //基于articleId查询文章数据
        ApArticle apArticle = apArticleService.getById(streamMsg.getArticleId());
        Long articleId = apArticle.getId();
        HotArticleVo hotArticleVo = BeanHelper.copyProperties(apArticle, HotArticleVo.class);
        //调用计算分值的方法
        this.computeScore(hotArticleVo);
        //当日分值计算方式，在原有权重的基础上再*3
        int score = hotArticleVo.getScore()*3;
        //获取频道id
        Integer channelId = apArticle.getChannelId();
        // 累加文章分值
        String redisKey =PRE_CHANNEL_FIX+channelId;
        redisTemplate.opsForZSet().incrementScore(redisKey,articleId.toString(),score);
        // 推荐频道，设置频道id为0，单独处理  累加文章分值
        String redisKeyRecommend = PRE_CHANNEL_FIX + 0;
        redisTemplate.opsForZSet().incrementScore(redisKeyRecommend,articleId.toString(),score);
    }

    @Override
    public List<ArticleDto> getHotArticle(Integer channelId) {
        //获取文章分值对应的文章id集合
        Set<String> set = redisTemplate.opsForZSet().reverseRange(PRE_CHANNEL_FIX + channelId, 0, -1);
        //        根据articleId 获取文章信息
        BoundHashOperations<String, String, String> hashOps = redisTemplate.boundHashOps(PRE_ARTICLE_FIX);
        List<ArticleDto> list = new ArrayList<>();
        for (String articleId : set) {
            String json = hashOps.get(articleId);
            //解析json字符串
            HotArticleVo hotArticleVo = JsonUtils.toBean(json, HotArticleVo.class);
            //转为ArticleDto
            ArticleDto articleDto = BeanHelper.copyProperties(hotArticleVo, ArticleDto.class);
            list.add(articleDto);
        }
        return list;
    }

    /**
     * 频道 新闻列表
     */
    private final String PRE_CHANNEL_FIX = "ld:article:hot:cid:";

    /**
     * 文章列表
     */
    private final String PRE_ARTICLE_FIX = "ld:article:aid";

    @Autowired
    private StringRedisTemplate redisTemplate;

    /**
     * 缓存热点文章到redis
     * @param hotArticleVoList
     */
    private void cacheHotArticleToRedisByChannel(List<HotArticleVo> hotArticleVoList) {
        for (HotArticleVo hotArticleVo : hotArticleVoList) {
            Long articleId = hotArticleVo.getId();
            Integer score = hotArticleVo.getScore();
            //获取文章的频道id
            Integer channelId = hotArticleVo.getChannelId();
            // 使用zset存储文章分值
            String redisKey =PRE_CHANNEL_FIX+channelId;
            redisTemplate.opsForZSet().add(redisKey,articleId.toString(),score);
            // 推荐频道，设置频道id为0，单独处理
            String redisKeyRecommend = PRE_CHANNEL_FIX + 0;
            redisTemplate.opsForZSet().add(redisKeyRecommend,articleId.toString(),score);
            // 使用hash数据类型存储文章内容
            String json = JsonUtils.toString(hotArticleVo);
            redisTemplate.opsForHash().put(PRE_ARTICLE_FIX,articleId.toString(),json);
        }

    }

    /**
     * 计算文章分值，获取热点文章列表
     * @param articleList
     * @return
     */
    private List<HotArticleVo> getHotApArticle(List<ApArticle> articleList) {
        List<HotArticleVo> hotArticleVoList = BeanHelper.copyWithCollection(articleList, HotArticleVo.class);
        for (HotArticleVo hotArticleVo : hotArticleVoList) {
            computeScore(hotArticleVo);
        }
        return hotArticleVoList;
    }

    /**
     * 计算文章分值
     * @param hotArticleVo
     */
    private void computeScore(HotArticleVo hotArticleVo) {
        Integer score =0;
        if(hotArticleVo.getLikes()!=null){
            //点赞一次 3分
            score += hotArticleVo.getLikes()*HOT_ARTICLE_LIKE_WEIGHT;
        }
        if(hotArticleVo.getViews() != null){
//          浏览一次  1分
            score += hotArticleVo.getViews();
        }
        if(hotArticleVo.getComment() != null){
//            评论一次 5分
            score += hotArticleVo.getComment() * ArticleConstans.HOT_ARTICLE_COMMENT_WEIGHT;
        }
        if(hotArticleVo.getCollection() != null){
//            收藏一次 8分
            score += hotArticleVo.getCollection() * ArticleConstans.HOT_ARTICLE_COLLECTION_WEIGHT;
        }
        hotArticleVo.setScore(score);

    }
}
